import os
from flask import Blueprint, render_template, redirect, url_for, flash, request, current_app, jsonify
from flask_login import login_required, current_user
from werkzeug.utils import secure_filename
from models.database import db, Image
from utils.data_processing import process_satellite_image, process_shp_file
import uuid
from PIL import Image as PILImage
import requests

data_bp = Blueprint('data', __name__, url_prefix='/data')

ALLOWED_EXTENSIONS = {
    'satellite': {'tif', 'tiff', 'jpg', 'jpeg', 'png'},
    'shp': {'shp', 'zip'}
}

def allowed_file(filename, file_type):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS[file_type]

@data_bp.route('/upload', methods=['GET', 'POST'])
@login_required
def upload():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('没有选择文件')
            return redirect(request.url)
        
        file = request.files['file']
        file_type = request.form.get('file_type', 'satellite')
        
        if file.filename == '':
            flash('没有选择文件')
            return redirect(request.url)
        
        if file and allowed_file(file.filename, file_type):
            filename = secure_filename(file.filename)
            # 添加唯一标识符防止文件名冲突
            unique_filename = f"{uuid.uuid4().hex}_{filename}"
            filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], unique_filename)
            file.save(filepath)
            
            # 创建数据库记录
            latitude = request.form.get('latitude')
            longitude = request.form.get('longitude')
            city = request.form.get('city')
            
            new_image = Image(
                filename=unique_filename,
                user_id=current_user.id,
                latitude=float(latitude) if latitude else None,
                longitude=float(longitude) if longitude else None,
                city=city if city else None,
                image_type=file_type
            )
            
            db.session.add(new_image)
            db.session.commit()
            
            flash('文件上传成功')
            
            # 对图像进行预处理
            if file_type == 'satellite':
                process_satellite_image(filepath, new_image.id)
            else:
                process_shp_file(filepath, new_image.id)
            
            return redirect(url_for('data.my_data'))
        else:
            flash(f'不支持的文件类型，支持的类型: {", ".join(ALLOWED_EXTENSIONS[file_type])}')
            return redirect(request.url)
    
    return render_template('data/upload.html')

@data_bp.route('/my-data')
@login_required
def my_data():
    images = Image.query.filter_by(user_id=current_user.id).order_by(Image.upload_date.desc()).all()
    return render_template('data/my_data.html', images=images)

@data_bp.route('/image/<int:image_id>')
@login_required
def image_detail(image_id):
    image = Image.query.get_or_404(image_id)
    
    # 确保用户只能查看自己的图像
    if image.user_id != current_user.id:
        flash('您无权访问该资源')
        return redirect(url_for('data.my_data'))
    
    # 检查预测功能是否可用
    prediction_available = False
    try:
        from routes.prediction import prediction_bp
        prediction_available = True
    except ImportError:
        prediction_available = False
    
    return render_template('data/image_detail.html', image=image, prediction_available=prediction_available)

@data_bp.route('/delete/<int:image_id>', methods=['POST'])
@login_required
def delete_image(image_id):
    image = Image.query.get_or_404(image_id)
    
    # 确保用户只能删除自己的图像
    if image.user_id != current_user.id:
        return jsonify({'success': False, 'message': '您无权删除该资源'}), 403
    
    # 删除相关文件
    try:
        filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], image.filename)
        if os.path.exists(filepath):
            os.remove(filepath)
        
        # 删除预测结果和分析结果
        for prediction in image.predictions:
            result_path = os.path.join(current_app.config['RESULTS_FOLDER'], prediction.result_filename)
            if os.path.exists(result_path):
                os.remove(result_path)
            
            for analysis in prediction.analysis_results:
                if analysis.chart_filename:
                    chart_path = os.path.join(current_app.config['RESULTS_FOLDER'], analysis.chart_filename)
                    if os.path.exists(chart_path):
                        os.remove(chart_path)
        
        # 删除数据库记录
        db.session.delete(image)
        db.session.commit()
        
        return jsonify({'success': True})
    
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 500

@data_bp.route('/convert', methods=['GET', 'POST'])
@login_required
def convert_format():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('未选择文件')
            return redirect(request.url)
        
        file = request.files['file']
        if file.filename == '':
            flash('未选择文件')
            return redirect(request.url)
        
        if file:
            # 检查文件格式是否为TIFF
            if not (file.filename.lower().endswith('.tif') or file.filename.lower().endswith('.tiff')):
                flash('只支持转换TIFF格式文件')
                return redirect(request.url)
            
            # 处理文件名
            filename = secure_filename(file.filename)
            original_path = os.path.join(current_app.config['UPLOAD_FOLDER'], filename)
            file.save(original_path)
            
            try:
                # 使用PIL打开并转换图像
                with PILImage.open(original_path) as img:
                    # 对于多波段图像，可能需要特殊处理
                    if img.mode != 'RGB':
                        if img.mode == 'RGBA':
                            # 有Alpha通道，转换为RGB
                            img = img.convert('RGB')
                        elif len(img.getbands()) > 3:
                            # 多波段图像，选择RGB波段
                            bands = img.getbands()
                            if len(bands) >= 3:
                                r_band = img.getchannel(0)
                                g_band = img.getchannel(1)
                                b_band = img.getchannel(2)
                                img = PILImage.merge('RGB', (r_band, g_band, b_band))
                            else:
                                # 少于3个波段，转换为灰度图
                                img = img.convert('RGB')
                    
                    # 保存为JPG
                    jpg_filename = os.path.splitext(filename)[0] + '.jpg'
                    jpg_path = os.path.join(current_app.config['UPLOAD_FOLDER'], jpg_filename)
                    img.save(jpg_path, 'JPEG', quality=95)
                    
                    # 创建新的图像记录
                    new_image = Image(
                        filename=f"{current_user.id}_{jpg_filename}",
                        user_id=current_user.id,
                        image_type='converted'
                    )
                    db.session.add(new_image)
                    db.session.commit()
                    
                    flash(f'文件已成功转换为JPG格式：{jpg_filename}')
                    return redirect(url_for('data.image_detail', image_id=new_image.id))
            except Exception as e:
                flash(f'转换过程中出错: {str(e)}')
                # 删除临时文件
                if os.path.exists(original_path):
                    os.remove(original_path)
                return redirect(request.url)
    
    return render_template('data/convert.html')

@data_bp.route('/edit_location/<int:image_id>', methods=['GET', 'POST'])
@login_required
def edit_location(image_id):
    image = Image.query.get_or_404(image_id)
    
    # 确保用户只能编辑自己的图像
    if image.user_id != current_user.id:
        flash('您无权访问该资源')
        return redirect(url_for('data.my_data'))
    
    if request.method == 'POST':
        try:
            # 从表单获取坐标和城市信息
            latitude = request.form.get('latitude')
            longitude = request.form.get('longitude')
            city = request.form.get('city')
            
            # 验证经纬度格式
            if latitude and longitude:
                latitude = float(latitude)
                longitude = float(longitude)
                
                # 验证经纬度范围
                if not (-90 <= latitude <= 90):
                    flash('纬度值必须在-90到90之间')
                    return redirect(url_for('data.edit_location', image_id=image_id))
                    
                if not (-180 <= longitude <= 180):
                    flash('经度值必须在-180到180之间')
                    return redirect(url_for('data.edit_location', image_id=image_id))
                
                # 如果用户没有提供城市名称，尝试通过坐标反向查询
                if not city:
                    try:
                        # 使用免费的反向地理编码API
                        response = requests.get(f"https://nominatim.openstreetmap.org/reverse?format=json&lat={latitude}&lon={longitude}&zoom=10&accept-language=zh-CN")
                        if response.status_code == 200:
                            data = response.json()
                            if 'address' in data:
                                # 尝试获取城市名称
                                city = data['address'].get('city') or data['address'].get('town') or data['address'].get('county')
                    except Exception as e:
                        # 如果API调用失败，不影响主要功能
                        print(f"反向地理编码错误: {str(e)}")
            
            # 更新图像信息
            image.latitude = latitude if latitude else None
            image.longitude = longitude if longitude else None
            image.city = city
            
            db.session.commit()
            
            flash('位置信息已更新')
            return redirect(url_for('data.image_detail', image_id=image_id))
            
        except ValueError:
            flash('请输入有效的经纬度值')
            return redirect(url_for('data.edit_location', image_id=image_id))
        except Exception as e:
            flash(f'更新位置信息时出错: {str(e)}')
            return redirect(url_for('data.edit_location', image_id=image_id))
    
    return render_template('data/edit_location.html', image=image) 